/*
 * @Author: Even
 * @Date: 2023-12-27 13:51:44
 * @LastEditors: Even
 * @LastEditTime: 2023-12-29 05:19:36
 * @FilePath: \opencos\opencos\manage_system\manage_system.cpp
 * @Description:
 */
#include <algorithm>
#include <rapidcsv.h>
#include <string>
#include <vector>

#include "customer/customer.h"
#include "customer/customer_member_rank.h"
#include "item/item.h"
#include "item/item_category.h"
#include "manage_system/manage_system.h"
#include "order/order.h"
#include "order/order_comment.h"
#include "order/order_status.h"

pManageSystem sys = std::make_shared<ManageSystem>();

void ManageSystem::read_item_from_file(const std::string &dir)
{
    rapidcsv::Document doc(dir);
    // read each column
    auto index       = doc.GetColumn<int>("index");
    auto category    = doc.GetColumn<ItemCategory>("category", Convert::StringToItemCategory);
    auto name        = doc.GetColumn<std::string>("name");
    auto price       = doc.GetColumn<float>("price");
    auto description = doc.GetColumn<std::string>("description");
    auto points      = doc.GetColumn<float>("points");
    auto sells       = doc.GetColumn<int>("sells");

    for(auto i : index)
    {
        auto k    = i - 1;
        Item item = Item(  //
            name[k],
            category[k],     //
            description[k],  //
            price[k],        //
            points[k],       //
            sells[k]         //
        );
        item_tb.push_back(item);
    };
};

void ManageSystem::read_customer_from_file(const std::string &dir)
{
    rapidcsv::Document doc(dir);
    // read each column
    auto index             = doc.GetColumn<int>("index");
    auto id                = doc.GetColumn<int>("id");
    auto name              = doc.GetColumn<std::string>("name");
    auto contact           = doc.GetColumn<std::string>("contact");
    auto total_consumption = doc.GetColumn<float>("total_consumption");
    auto member_rank       = doc.GetColumn<MemberRank>("member_rank", Convert::String2MemberRank);

    for(auto i : index)
    {
        auto k        = i - 1;
        auto customer = Customer(
            id[k],                 //
            name[k],               //
            contact[k],            //
            total_consumption[k],  //
            member_rank[k]
        );
        customer_dict[id[k]] = customer;
    }
}

void ManageSystem::read_order_from_file(const std::string &dir)
{
    rapidcsv::Document doc(dir);
    // read each column
    auto index         = doc.GetColumn<int>("index");
    auto serial_number = doc.GetColumn<int>("serial_number");
    auto create_time   = doc.GetColumn<time_point>("create_time", Convert::StringToTimePoint);
    auto finish_time   = doc.GetColumn<time_point>("finish_time", Convert::StringToTimePoint);
    auto cancel_time   = doc.GetColumn<time_point>("cancel_time", Convert::StringToTimePoint);
    auto customer_id   = doc.GetColumn<int>("customer_id");
    auto ordered_items = doc.GetColumn<std::vector<OrderItem>>("ordered_items", Convert::StringToOrderItems);
    auto total_price   = doc.GetColumn<float>("total_price");
    // auto order_comment = doc.GetColumn<OrderComment>("order_comment");
    auto order_status = doc.GetColumn<OrderStatus>("order_status", Convert::StringToOrderStatus);
    for(auto i : index)
    {
        auto  k     = i - 1;
        Order order = Order(
            serial_number[k],  //
            create_time[k],    //
            finish_time[k],    //
            cancel_time[k],    //
            customer_id[k],    //
            ordered_items[k],  //
            total_price[k],    //
            // order_comment[k],  //
            order_status[k]  //
        );
        order_tb.push_back(order);
    }
}

void ManageSystem::write_item_to_file(const std::string &dir)
{
    rapidcsv::Document       doc;
    std::vector<int>         index;
    std::vector<std::string> name;
    std::vector<std::string> category;
    std::vector<std::string> description;
    std::vector<float>       price;
    std::vector<float>       points;
    std::vector<int>         sells;

    for(auto i = 0; i < item_tb.size(); i++)
    {
        auto k = i + 1;
        index.push_back(k);
        name.push_back(item_tb[i].get_name());
        category.push_back(Convert::ItemCategoryToString(item_tb[i].get_category()));
        description.push_back(item_tb[i].get_description());
        price.push_back(item_tb[i].get_price());
        points.push_back(item_tb[i].get_points());
        sells.push_back(item_tb[i].get_sells());
    };
    // write each column
    doc.SetColumnName(0, "index");
    doc.SetColumnName(1, "name");
    doc.SetColumnName(2, "category");
    doc.SetColumnName(3, "description");
    doc.SetColumnName(4, "price");
    doc.SetColumnName(5, "points");
    doc.SetColumnName(6, "sells");

    doc.SetColumn("index", index);
    doc.SetColumn("name", name);
    doc.SetColumn("category", category);
    doc.SetColumn("description", description);
    doc.SetColumn("price", price);
    doc.SetColumn("points", points);
    doc.SetColumn("sells", sells);

    doc.Save(dir);
}

void ManageSystem::write_customer_to_file(const std::string &dir)
{
    rapidcsv::Document       doc;
    std::vector<int>         index;
    std::vector<int>         id;
    std::vector<std::string> name;
    std::vector<std::string> contact;
    std::vector<float>       total_consumption;
    std::vector<std::string> member_rank;

    auto i = 1;
    for(auto &[id_, customer] : customer_dict)
    {
        index.push_back(i++);
        id.push_back(customer.get_id());
        name.push_back(customer.get_name());
        contact.push_back(customer.get_contact());
        total_consumption.push_back(customer.get_total_consumption());
        member_rank.push_back(Convert::MemberRank2String(customer.get_member_rank()));
    };
    // write each column
    doc.SetColumnName(0, "index");
    doc.SetColumnName(1, "id");
    doc.SetColumnName(2, "name");
    doc.SetColumnName(3, "contact");
    doc.SetColumnName(4, "total_consumption");
    doc.SetColumnName(5, "member_rank");

    doc.SetColumn("index", index);
    doc.SetColumn("id", id);
    doc.SetColumn("name", name);
    doc.SetColumn("contact", contact);
    doc.SetColumn("total_consumption", total_consumption);
    doc.SetColumn("member_rank", member_rank);

    doc.Save(dir);
}

void ManageSystem::write_order_to_file(const std::string &dir)
{
    rapidcsv::Document doc;

    std::vector<int>         index;
    std::vector<int>         serial_number;
    std::vector<std::string> create_time;
    std::vector<std::string> finish_time;
    std::vector<std::string> cancel_time;
    std::vector<int>         customer_id;
    std::vector<std::string> ordered_items;
    std::vector<float>       total_price;
    // std::vector<std::string> order_comment;
    std::vector<std::string> order_status;

    for(auto i = 0; i < order_tb.size(); i++)
    {
        auto k = i + 1;
        index.push_back(k);
        serial_number.push_back(order_tb[i].get_serial_number());
        create_time.push_back(Convert::TimePointToString(order_tb[i].get_create_time()));
        finish_time.push_back(Convert::TimePointToString(order_tb[i].get_finish_time()));
        cancel_time.push_back(Convert::TimePointToString(order_tb[i].get_cancel_time()));
        customer_id.push_back(order_tb[i].get_customer_id());
        ordered_items.push_back(Convert::OrderItemsToString(order_tb[i].get_ordered_items()));
        total_price.push_back(order_tb[i].get_total_price());
        order_status.push_back(Convert::OrderStatusToString(order_tb[i].get_status()));
    }
    // write each column
    doc.SetColumnName(0, "index");
    doc.SetColumnName(1, "serial_number");
    doc.SetColumnName(2, "create_time");
    doc.SetColumnName(3, "finish_time");
    doc.SetColumnName(4, "cancel_time");
    doc.SetColumnName(5, "customer_id");
    doc.SetColumnName(6, "ordered_items");
    doc.SetColumnName(7, "total_price");
    // doc.SetColumnName(8, "order_comment");
    doc.SetColumnName(8, "order_status");

    doc.SetColumn("index", index);
    doc.SetColumn("serial_number", serial_number);
    doc.SetColumn("create_time", create_time);
    doc.SetColumn("finish_time", finish_time);
    doc.SetColumn("cancel_time", cancel_time);
    doc.SetColumn("customer_id", customer_id);
    doc.SetColumn("ordered_items", ordered_items);
    doc.SetColumn("total_price", total_price);
    // doc.SetColumn("order_comment", order_comment);
    doc.SetColumn("order_status", order_status);

    doc.Save(dir);
}